import {toRaw, unref} from "vue";
import {defineStore} from "pinia";
import {RouteRecordRaw} from "vue-router";
import {store} from "@/store";
import {asyncRoutes, constantRouter} from "@/router/index";
import {generatorDynamicRouter} from "@/router/generator-routers";
import {useProjectSetting} from "@/hooks/setting/useProjectSetting";
import menuApi from "@/api/menuApi";
import {HttpCode} from "@";
import {Layer} from "slash-layer";
import SlashAppContext from "../../context/SlashAppContext";

interface TreeHelperConfig {
  id: string;
  children: string;
  pid: string;
}

const DEFAULT_CONFIG: TreeHelperConfig = {
  id: "id",
  children: "children",
  pid: "pid"
};

const getConfig = (config: Partial<TreeHelperConfig>) => Object.assign({}, DEFAULT_CONFIG, config);

export interface IAsyncRouteState {
  menus: RouteRecordRaw[];
  routers: any[];
  addRouters: any[];
  keepAliveComponents: string[];
  isDynamicAddedRoute: boolean;
}

function filter<T = any>(
  tree: T[],
  func: (n: T) => boolean,
  config: Partial<TreeHelperConfig> = {}
): T[] {
  config = getConfig(config);
  const children = config.children as string;

  function listFilter(list: T[]) {
    return list
      .map((node: any) => ({...node}))
      .filter((node) => {
        node[children] = node[children] && listFilter(node[children]);
        return func(node) || (node[children] && node[children].length);
      });
  }

  return listFilter(tree);
}

export const useAsyncRouteStore = defineStore({
  id: "app-async-route",
  state: (): IAsyncRouteState => ({
    menus: [],
    routers: constantRouter,
    addRouters: [],
    keepAliveComponents: [],
    // Whether the route has been dynamically added
    isDynamicAddedRoute: false
  }),
  getters: {
    getMenus(): RouteRecordRaw[] {
      return this.menus;
    },
    getIsDynamicAddedRoute(): boolean {
      return this.isDynamicAddedRoute;
    }
  },
  actions: {
    getRouters() {
      return toRaw(this.addRouters);
    },
    setDynamicAddedRoute(added: boolean) {
      this.isDynamicAddedRoute = added;
    },
    // 设置动态路由
    setRouters(routers) {
      this.addRouters = routers;
      this.routers = constantRouter.concat(routers);
    },
    setMenus(menus) {
      // 设置动态路由
      this.menus = menus;
    },
    setKeepAliveComponents(compNames) {
      // 设置需要缓存的组件
      this.keepAliveComponents = compNames;
    },
    async generateRoutes(data) {
      console.log("生成菜单");
      let accessedRouters;
      const permissionsList = data.permissions || [];
      const routeFilter = (route) => {
        const {meta} = route;
        const {permissions} = meta || {};
        if (!permissions) return true;
        return permissionsList.some((item) => permissions.includes(item.value));
      };
      const {getPermissionMode} = useProjectSetting();
      const permissionMode = unref(getPermissionMode);
      if (permissionMode === "BACK") {
        // 动态获取菜单
        try {
          accessedRouters = await generatorDynamicRouter();
          console.log("菜单:{}", accessedRouters);
        } catch (error) {
          console.log(error);
        }
      } else {
        try {
          //过滤账户是否拥有某一个权限，并将菜单从加载列表移除
          accessedRouters = filter(asyncRoutes, routeFilter);
        } catch (error) {
          console.log(error);
        }
      }
      accessedRouters = accessedRouters.filter(routeFilter);
      this.setRouters(accessedRouters);
      console.log(accessedRouters);
      const menuMsg = await menuApi.selectCurrentAppAndUserMenu(null);
      if (menuMsg.code != HttpCode.OK) {
        Layer.error(menuMsg.msg);
        SlashAppContext.getRouter()?.push({
          path: SlashAppContext.getAppConfig().loginPath
        });
        return null;
      }
      const menuList = await createMenuRouteRecordRaw(menuMsg.data);
      this.setMenus([
        ...menuList
      ]);
      return toRaw(accessedRouters);
    }
  }
});

// @ts-ignore
export async function createMenuRouteRecordRaw(menuList: any) {
  const result: any[] = [];
  for (let i = 0; i < menuList.length; i++) {
    const it = menuList[i];
    it.name = it.id;
    const meta = {} as any;
    meta.title = it.resourceName;
    it.meta = meta;
    it.redirect = it.resourceUrl;
    if (it.children.length > 0) {
      it.children = await createMenuRouteRecordRaw(it.children);
    } else {
      delete it.children;
    }
    result.push(it);
  }
  return result;
};

// Need to be used outside the setup
export function useAsyncRouteStoreWidthOut() {
  return useAsyncRouteStore(store);
}
